package com.personal.service.Impl;

import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import com.personal.bo.FindPasswordBO;
import com.personal.bo.UserBO;
import com.personal.constant.VipConstant;
import com.personal.enums.Sex;
import com.personal.enums.UserEnum;
import com.personal.exception.ExceptionUtils;
import com.personal.mapper.DynamicMapper;
import com.personal.mapper.GoldCoinMapper;
import com.personal.mapper.UsersMapper;
import com.personal.pojo.GoldCoin;
import com.personal.pojo.Users;
import com.personal.service.EmailService;
import com.personal.service.UserService;
import com.personal.service.dto.EmailDto;
import com.personal.utils.DateUtil;
import com.personal.utils.MD5Utils;
import com.personal.utils.RedisUtils;
import com.personal.utils.Result;
import io.lettuce.core.RedisURI;
import lombok.extern.slf4j.Slf4j;
import org.n3y.idworker.Sid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.security.PrivateKey;
import java.util.Collections;
import java.util.Date;


@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private UsersMapper usersMapper;

    @Autowired
    private DynamicMapper dynamicMapper;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private EmailService emailService;

    @Autowired
    private GoldCoinMapper goldCoinMapper;

    @Value("${code.expiration}")
    private Long expiration;

    @Autowired
    private Sid sid;

    private static final String USER_FACE = "http://123456";

    /**
     * 判断用户名是否存在
     * @param username
     */
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    @Override
    public boolean queryUsernameIsExist(String username) {
        log.info("开始执行判断用户是否存在接口");
        Users result = usersMapper.queryUsernameIsExist(username);
        return result == null ? false : true;
    }

    /**
     * 创建用户
     * @param userBO
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public Users createUser(UserBO userBO) {
        log.info("开始执行创建用户接口");
        Users users = new Users();
        users.setUsername(userBO.getUsername());
        try {
            users.setPassword(MD5Utils.getMD5Str(userBO.getPassword()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        //默认用户昵称和用户名一致
        users.setNickname(userBO.getUsername());
        users.setEmail(userBO.getEmail());
        //设置用户默认头像
        users.setFace(USER_FACE);
        //设置默认的生日
        users.setBirthday(DateUtil.stringToDate("1900-01-01"));
        users.setSex(Sex.secret.type);
        users.setIsVip(VipConstant.AVERAGE_USER);

        //设置默认头像
        users.setFace("http://192.168.215.154:9000/itmall/默认头像.jpg");

        //用户注册时间和修改时间
        users.setCreateTime(new Date());
        users.setUpdateTime(new Date());

        usersMapper.regist(users);

        //用户注册成功后自动创建账户
        goldCoinMapper.createAccount(users.getId());

        return users;
    }

    /**
     * 查询用户名和密码是否对应匹配
     * @param username
     * @param password
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public Users queryUserForLogin(String username, String password) {
        log.info("开始执行登录接口");
        Example userExample = new Example(Users.class);
        Example.Criteria userCriteria = userExample.createCriteria();

        userCriteria.andEqualTo("username", username);
        userCriteria.andEqualTo("password", password);

        Users result = usersMapper.selectOneByExample(userExample);
        if (result == null){
            ExceptionUtils.error(UserEnum.USER_OR_PASSWORD_ERROR);
        }

        //将用户登录信息写入dynamic
        dynamicMapper.add(result.getId(),"登录了系统");

        return result;
    }

    /**
     * 发送邮箱验证码
     * @param email
     */
    @Override
    public void seadEmailCode(String email) {
        log.info("开始执行发送邮箱验证码接口");
        //检查邮箱是否存在
        if (usersMapper.queryEmailIsExist(email) != 0){
            ExceptionUtils.error(UserEnum.EMAIL_IS_EXIST);
        }

        //获取发送验证码的HTML模板
        TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("static",TemplateConfig.ResourceMode.CLASSPATH));
        Template template = engine.getTemplate("code.ftl");

        // 从redis缓存中尝试获取验证码
        Object code = redisUtils.get(email);
        if (code == null) {
            // 如果在缓存中未获取到验证码，则产生6位随机数，放入缓存中
            code = RandomUtil.randomNumbers(6);
            if (!redisUtils.set(email, code, expiration)) {
                throw new RuntimeException("后台缓存服务异常");
            }
        }
        // 发送验证码
        emailService.send(new EmailDto(Collections.singletonList(email),
                "邮箱验证码，欢迎注册该站", template.render(Dict.create().set("code", code))));
    }

    /**
     * 找回密码
     * @param findPasswordBO
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public Result findPassword(FindPasswordBO findPasswordBO) {
        log.info("找回密码接口");

        //id参数判断
        if (findPasswordBO.getUserId() == null || findPasswordBO.getUserId() <= 0){
            ExceptionUtils.error(UserEnum.USER_ID_IS_ERROR);
        }

        //判断验证码是否正确
        String code = (String) redisUtils.get(findPasswordBO.getEmail());
        if (StrUtil.isBlank(code) || !findPasswordBO.getCode().equals(code)){
            ExceptionUtils.error(UserEnum.EMAIL_CODE_ERROR);
        }else {
            redisUtils.del(findPasswordBO.getEmail());
        }

        usersMapper.updatePassword(findPasswordBO.getNewPassword(),findPasswordBO.getUserId());

        return Result.success();
    }

}
